package classfile

/*
各种属性表达的信息也各不相同， 无法用统一的结构来定义。
属性是可以扩展的，不同虚拟机实现可以定义自己的属性类型。
虚拟机使用属性名来区别不通的属性。
属性数据放在属性名后的u1表中，虚拟机可以跳过自己无法识别的属性。

属性表中存放的属性名实际上是常量池索引
 */
type AttributeInfo interface {
	ReadInfo(reader *ClassReader)
}

func readAttributes(reader *ClassReader, cp ConstantPool) []AttributeInfo {
	count := reader.ReadUint16()
	attributes := make([]AttributeInfo, count)
	for i := range attributes {
		attributes[i] = readAttribute(reader, cp)
	}
	return attributes
}

func readAttribute(reader *ClassReader, cp ConstantPool) AttributeInfo {
	nameIndex := reader.ReadUint16()
	name := cp.getUtf8(nameIndex)
	length := reader.ReadUint32()
	info := newAttributeInfo(name, length, cp)
	info.ReadInfo(reader)
	return info
}

func newAttributeInfo(attrName string, attrLen uint32, cp ConstantPool) AttributeInfo {
	switch attrName {
		case Code: return &CodeAttribute{cp: cp}		
		case ConstantValue: return &ConstantValueAttribute{}
		case Deprecated: return &DeprecatedAttribute{}
		case Exceptions: return &ExceptionsAttribute{}
		case LineNumberTable: return &LineNumberTableAttribute{}
		case LocalVariableTable: return &LocalVariableTableAttribute{}
		case SourceFile: return &SourceFileAttribute{cp:cp}
		case Synthetic: return &SyntheticAttribute{}
		default:return &UnparsedAttribute{attrName, attrLen, nil}
	}
	return nil
}